﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Gueei.Gallery.Core.Entities;
using Gueei.Gallery.Core.Repositories;
using Gueei.Gallery.Core.ViewModels;

namespace Gueei.Gallery.Core.Services
{
	public class BatchImportService
	{
		private readonly IImageService _imageService;
		private readonly IDisplayProfileRepository _displayProfile;
		private readonly string _tempStoragePath;

		private static Dictionary<Guid, UploadBatch> _uploadBatches = new Dictionary<Guid, UploadBatch>();

		/// <summary>
		/// What it does? 
		/// 1. Save the uploaded files in a temp location
		/// 2. For each single image file, wait for additional details
		/// 3. Save all via imageService once approved
		/// 4. Remove those not approved from saving
		/// 5. Remove everything once the timeout expired
		/// TODO: 6. Should support management function
		/// </summary>
		public BatchImportService(IDisplayProfileRepository displayProfile, 
			IImageService imageService,
			string tempStoragePath)
		{
			_imageService = imageService;
			_tempStoragePath = Path.Combine(tempStoragePath, "batchupload");
			_displayProfile = displayProfile;
			Directory.CreateDirectory(tempStoragePath);
		}

		public UploadBatch GetUploadBatch(Guid batchId)
		{
			return _uploadBatches[batchId];
		}

		public UploadBatch StartNewBatch()
		{
			var batchId = Guid.NewGuid();

			var viewmodel = new UploadBatch { BatchId = batchId, CreateDate = DateTime.Now };

			Directory.CreateDirectory(GetBatchTempDirectoryName(viewmodel));

			_uploadBatches.Add(batchId, viewmodel);

			// TODO: Cleanup of expired batches

			return viewmodel;
		}

		private string GetBatchTempDirectoryName(UploadBatch batch)
		{
			return Path.Combine(_tempStoragePath, "batch_" + batch.BatchId);
		}

		private string GetFileNameInBatchTempDirectory(UploadBatch batch, Guid fileId, string originalFileName)
		{
			return Path.Combine(GetBatchTempDirectoryName(batch), fileId.ToString() + Path.GetExtension(originalFileName));
		}

		public TempImage AddToBatch(UploadBatch batch, Stream data, string filename)
		{
			// Save the file
			var id = Guid.NewGuid();
			var file = new FileInfo(GetFileNameInBatchTempDirectory(batch, id, filename));
			using (var fs = file.Create())
			{
				data.CopyTo(fs);
			}
			TempImage result = new TempImage()
			                   	{
			                   		Name = filename,
			                   		TempId = id,
			                   		OriginalFileName = filename,
			                   		FileInfo = file,
			                   		MimeType = Image.GetMimeTypeFromFileName(filename)
			                   	};
			batch.TempImages.Add(result);
			return result;
		}

		public byte[] GetPreview(Guid batchId, Guid tempId, out string contentType)
		{
			var batch = this.GetUploadBatch(batchId);
			if (batch == null) throw new ArgumentException("Batch not found");

			var imageFile = batch.TempImages.Where(i => i.TempId.Equals(tempId)).FirstOrDefault();
			if (imageFile == null) throw new ArgumentException("Requested File not found in the supplied batch");

			var data = new byte[imageFile.FileInfo.Length];
			using (var fs = imageFile.FileInfo.OpenRead())
			{
				fs.Read(data, 0, (int)imageFile.FileInfo.Length);
			}

			contentType = imageFile.MimeType;

			return _displayProfile
				.ThumbnailDisplayProfile
				.ConvertImage(data,contentType);
		}


		// Finalize the batch
		public IEnumerable<Image> ConfirmBatch(UploadBatch batch)
		{
			foreach(var image in batch.TempImages)
			{
				yield return _imageService.SaveNewImage(image.Tags,
				                           image.Name, image.Description, image.OriginalFileName, image.MimeType, batch.Creator,
				                           image.FileInfo);
			}
			RemoveBatch(batch);
		}

		private void RemoveBatch(UploadBatch batch)
		{
			Directory.Delete(this.GetBatchTempDirectoryName(batch), true);
			_uploadBatches.Remove(batch.BatchId);
		}
	}
}
